﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.Reflection.Emit;
using System.Reflection;
using System.Collections;
using System.Data.Entity.ModelConfiguration;

namespace COM.Data
{
    public class SqlQueryService
    {
        private DbContext context;
        public SqlQueryService(DbContext context)
        {
            this.context = context;
        }

        class MapCacheItem
	    {
		    //public EntityTypeConfiguration<T> ConfigurationMap{get;set;}
		    public Type MapType {get;set;}
		    public Dictionary<string,string> PropertyNameMap{get;set;}
	    }

        static private Dictionary<string,MapCacheItem> MapCache = new Dictionary<string,MapCacheItem>();

        private MapCacheItem CreateMapCacheItem<T>(string typeName,EntityTypeConfiguration<T> map) where T : class,new()
        {
            dynamic mapDynamic = new AccessPrivateWrapper(map);
            dynamic m = new AccessPrivateWrapper(mapDynamic.Configuration);
            dynamic configList = m.PrimitivePropertyConfigurations;
            Dictionary<string, string> entityMap = new Dictionary<string, string>();
            Dictionary<string, Type> dynamicTypePropList = new Dictionary<string, Type>();
            foreach (var c in configList)
            {
                //System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive.PrimitivePropertyConfiguration
                //System.Data.Entity.ModelConfiguration.Configuration.PrimitivePropertyConfiguration p;

                dynamic config = new AccessPrivateWrapper(c);
                Type type = typeof(int);
                string pName = string.Empty;
                foreach (var configItem in config.Key)
                {
                    PropertyInfo p = configItem as PropertyInfo;
                    type = configItem.PropertyType;
                    pName = p.Name;
                }
                dynamic value = new AccessPrivateWrapper(config.Value);
                var item = new { PropertyName = pName, ColumnName = value.ColumnName };
                //var type = typeof(T).GetProperty(item.PropertyName).DeclaringType;
                dynamicTypePropList.Add(item.ColumnName, type);
                entityMap.Add(item.ColumnName, item.PropertyName);
            }
            Type resultType = CreateDynamicType.Instance.CreateTempType(typeName, dynamicTypePropList);
            return new MapCacheItem() { MapType = resultType, PropertyNameMap = entityMap };
        }

        #region DynamicExecuteSql
        public IEnumerable<T> DynamicExecuteSql<T>(EntityTypeConfiguration<T> map, string sql, params object[] parameters) where T : class,new()
        {
            string mapTypeName = map.GetType().FullName;
            if (!MapCache.ContainsKey(mapTypeName))
                MapCache.Add(mapTypeName, this.CreateMapCacheItem(mapTypeName,map));
            MapCacheItem mapCacheItem = MapCache[mapTypeName];
            var queryList = context.Database.SqlQuery(mapCacheItem.MapType, sql, parameters);
            foreach (var item in queryList)
            {
                var entity = new T();
                EntityReflectService.Instance.CopyEntityProperty(item, entity, mapCacheItem.PropertyNameMap);
                yield return entity;
            }
        }

 
        #endregion 
        
    }



        
}
